package com.tang.script.command;

import com.tang.script.extrator.ConstantsExtractor;
import com.tang.script.extrator.FunctionsExtractor;
import com.tang.script.extrator.VariablesExtractor;
import com.tang.script.functions.ScriptFunction;
import com.tang.script.syntax.SyntaxChecker;
import com.tang.script.variable.Constant;
import com.tang.script.variable.Variable;
import com.tang.script.variable.VariablesContainer;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

@Getter
@Setter
public class TranslateCommand extends AbstractScriptCommand<String> {

    private Class resultType = Object.class;

    @Builder
    public TranslateCommand(String scriptText, VariablesContainer variablesContainer) {
        super(scriptText, variablesContainer);
    }

    @Override
    public String execute() {

        initCommand();

        ConstantsExtractor constantsExtractor = ConstantsExtractor.get();
        constantsExtractor.extracte(this);

        VariablesExtractor variablesExtractor = VariablesExtractor.get();
        variablesExtractor.extracte(this);

        FunctionsExtractor functionsExtractor = FunctionsExtractor.get();
        functionsExtractor.extracte(this);

        SyntaxChecker syntaxChecker = new SyntaxChecker();
        syntaxChecker.checkAndThrow(this, resultType);

        replaceVariables();
        replaceConstants();
        replaceFunctions();
        return resolvedScriptText;
    }

    private void replaceFunctions() {
        List<String> functions = getFunctions();
        for (String function : functions) {
            Object o = getScriptEngine().loadFunction(function);
            try {
                ScriptFunction annotation = o.getClass().getAnnotation(ScriptFunction.class);
                if (Objects.isNull(annotation)) {
                    for (Method method : o.getClass().getMethods()) {
                        annotation = method.getAnnotation(ScriptFunction.class);
                        if(Objects.nonNull(annotation)) break;
                    }
                }
                if (Objects.nonNull(annotation)) {
                    resolvedScriptText = resolvedScriptText.replaceAll(function + "." + function, annotation.functionName());
                }
            } catch (Exception e) {
            }
        }
    }

    private void replaceConstants() {
        for (String key : constants.keySet()) {
            Constant variable = constants.get(key);
            resolvedScriptText = resolvedScriptText.replaceAll(key, variable.getTitle());
        }
    }

    private void replaceVariables() {
        for (String key : variables.keySet()) {
            Variable variable = variables.get(key);
            resolvedScriptText = resolvedScriptText.replaceAll(key, variable.getTitle());
        }
    }

    @Override
    public Class getResultClass() {
        return String.class;
    }
}
